#include "Common.h"
#include "RenderStatus.h"
#include "Render.h"

void BoundShaderState::Set()
{
	LPDIRECT3DDEVICE9 pDevice = Render::Instance().getDevice();

	VERIFY_D3D(pDevice->SetVertexDeclaration(VertexDeclaration));
	VERIFY_D3D(pDevice->SetVertexShader(VertexShader));
	VERIFY_D3D(pDevice->SetPixelShader(PixelShader));
}

void SetBlendState(
	EBlendOperation ColorBlendOp,
	EBlendFactor ColorSrcBlend,
	EBlendFactor ColorDestBlend,
	EBlendOperation AlphaBlendOp,
	EBlendFactor AlphaSrcBlend,
	EBlendFactor AlphaDestBlend,
	ECompareFunction AlphaTest,
	BYTE AlphaRef)
{
	LPDIRECT3DDEVICE9 pDevice = Render::Instance().getDevice();
	
	if (ColorBlendOp != BLENDOP_ADD || ColorDestBlend != BLEND_ZERO || ColorSrcBlend != BLEND_ONE ||
		AlphaBlendOp != BLENDOP_ADD || AlphaDestBlend != BLEND_ZERO || AlphaSrcBlend != BLEND_ONE)
	{
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_BLENDOP, ColorBlendOp));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_SRCBLEND, ColorSrcBlend));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_DESTBLEND, ColorDestBlend));
	}
	else
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE));

	if (ColorDestBlend != AlphaDestBlend || ColorSrcBlend != AlphaSrcBlend)
	{
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_BLENDOPALPHA, AlphaBlendOp));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_SRCBLENDALPHA, AlphaSrcBlend));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_DESTBLENDALPHA, AlphaDestBlend));
	}
	else
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE));

	if (AlphaTest != CMP_ALWAYS)
	{
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ALPHAFUNC, AlphaTest));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ALPHAREF, AlphaRef));
	}
	else
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE));
}

void SetDepthState(
	bool EnableDepthWrite,
	ECompareFunction DepthTest)
{
	LPDIRECT3DDEVICE9 pDevice = Render::Instance().getDevice();
	if (EnableDepthWrite || DepthTest != CMP_ALWAYS)
	{
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ZENABLE, TRUE));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ZWRITEENABLE, EnableDepthWrite));
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ZFUNC, DepthTest));
	}
	else
		VERIFY_D3D(pDevice->SetRenderState(D3DRS_ZENABLE, FALSE));
}

void SetRasterizerState(
	EFILLMODE FillMode,
	ECULL CullMode,
	FLOAT DepthBias,
	FLOAT SlopeScaleDepthBias)
{
	LPDIRECT3DDEVICE9 pDevice = Render::Instance().getDevice();

	VERIFY_D3D(pDevice->SetRenderState(D3DRS_FILLMODE, FillMode));
	VERIFY_D3D(pDevice->SetRenderState(D3DRS_CULLMODE, CullMode));
	// Add the global depth bias
	VERIFY_D3D(pDevice->SetRenderState(D3DRS_DEPTHBIAS, *(DWORD*)(&DepthBias)));
	VERIFY_D3D(pDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)(&DepthBias)));
}

void SetViewport(UINT X, UINT Y, UINT W, UINT H, FLOAT MinZ,FLOAT MaxZ)
{
	D3DVIEWPORT9 Viewport = { X, Y, W, H, MinZ, MaxZ };
	VERIFY_D3D(Render::Instance().getDevice()->SetViewport(&Viewport));
}

void Clear(bool bClearColor, DWORD Color, bool bClearDepth, FLOAT Depth, bool bClearStencil, DWORD Stencil)
{
	DWORD Flags = 0;
	if(bClearColor) Flags |= D3DCLEAR_TARGET;
	if(bClearDepth) Flags |= D3DCLEAR_ZBUFFER;
	if(bClearStencil) Flags |= D3DCLEAR_STENCIL;

	VERIFY_D3D(Render::Instance().getDevice()->Clear(0, NULL, Flags, Color, Depth, Stencil));
}